/**********************************************************************
 * 
 * Name: UpsertOrderREST
 * Object: Order__c, Order_Product__c
 * Purpose: Upsert Order and Order Products list from NC
 * Requirement:
 * Author: kittylau (382376269@qq.com)
 * Create Date: 2017-01-12
 * Modify History: 
 * 
 * @Url: /services/apexrest/CRM/upsertOrderREST
 * 接收的Json数据格式:
   {
    "data":[
        {
            //主表数据
            "salecode":"销售订单号",
            "sale_hid":"销售订单主表ID",
            "corpcode":"公司编码",
            "corpname":"公司名称",
            "custcode":"客户编码",
            "custname":"客户名称",
            "currtypename":"币种",
            "saledate":"订单日期",
            "deptname":"部门",
            "ywyname":"业务员",
            "shaddr":"收货地址",
            "kpdw":"开票单位",
            "skxy":"收款协议",
            "zdkh":"终端客户",
            //从表数据",
            "sale_bid":"销售订单从表ID",
            "invcode":"存货编码",
            "invname":"存货名称",
            "invdm":"存货代码",
            "pzwh":"批准文号",
            "nnum":"数量",
            "noriginalcurtaxprice":"原币含税单价",
            "noriginalcursummny":"原币价税合计",
            "noriginalcurprice":"原币无税单价",
            "noriginalcurmny":"原币无税金额",
            "ts":"最后更新时间"
            //v1.4版本新增
            "rowno":"行号",
            "invspec":"规格",
            "invtype":"型号",
            "cbiztype":"业务流程",
            "vsalestruname":"销售组织",
            "bodyname":"库存组织",
            "kpfs":"开票方式",
            "xsqy":"销售区域",
            "hbfs":"开票合并方式",
            "jshj":"整单价税合计",
            "memo":"备注",
            "tsyq":"客户特殊要求",
            "iszx":"是否直销",
            "prodlinename":"产品线",
            "ntaxrate":"税率",
            "jldw":"单位",
            "ndiscountrate":"整单折扣",
            "nitemdiscountrate":"单品折扣",
            "noriginalcurnetprice":"无税净价",
            "noriginalcurtaxnetprice":"含税净价",
            "noriginalcurdiscountmny":"折扣额",
            "tconsigntime":"计划发货时间",
            "jmb":"当前价目表",
            "norgqttaxprc":"报价单位本币含税单价",
            "cinvbasid":"存货基本档案pk"
        },
        {...}
        ]
   }
*  返回的Json数据格式：
  {
    "result":"0 OR 1 , 1表示成功，0表示失败", 
    "result_msg":"成功为空，失败时为失败原因信息",
    "ts":"所有记录中,更新时间最近的那一条记录的更新时间"
  }
*************************************************************************/
@RestResource(urlMapping='/CRM/upsertOrderREST/*')
global without sharing class UpsertOrderREST {
    @HttpPost
    global static RestReturnMessage upsertOrder(List<OrderRestArgs> data) {
        RestReturnMessage msg = null;
        try{
            if(data.size() > 0 ){
                msg = doUpsertOrder(data);
            }else{
                throw new DmlException('没有数据');
            }
        }
        catch(Exception e){
            System.debug(LoggingLevel.INFO, '*** 错误信息: ' + e.getMessage() );
            System.debug(LoggingLevel.INFO, '*** 错误跟踪: ' + e.getStackTraceString());
            msg = Utils.getRestReturnMessage(false, e.getMessage() + ' - ' + e.getStackTraceString(),new List<Map<String,String>>());
        }
        System.debug(LoggingLevel.INFO, '*** 订单调用返回结果: ' + msg );
        return msg;
    }

    //得到POST数据，完成Order数据的插入或更新
    global static RestReturnMessage doUpsertOrder (List<OrderRestArgs> data) {
        RestReturnMessage message = null;
        Datetime minTs = Datetime.valueOf('2099-01-01 00:00:00');
        Datetime maxTs = Datetime.valueOf(Utils.MIN_DATE_TIME);
        System.debug(LoggingLevel.INFO, '*** Order Data FROM NC: ' + data);

        //保存传过来的Order编号: 2017.7.5 :订单pk 
        Map<String,String> mapCodes = new Map<String,String>();
        //保存传过来的客户编号
        Map<String,String> mapAccount = new Map<String,String>();
        //保存传过来的产品编号
        Map<String,String> mapProduct = new Map<String,String>();
        for(OrderRestArgs ord : data){
            if(ord.salecode != null){
                //因为订单是主从表结构，但是NC传过来的数据是扁平化后报表样式的(主表和从表JOIN后的数据)
                /*if(!mapCodes.containsKey(ord.salecode)){
                    mapCodes.put(ord.salecode,ord.salecode);
                }*/
                if(!mapCodes.containsKey(ord.sale_hid)){
                    mapCodes.put(ord.sale_hid,ord.sale_hid);
                }
                if(ord.custcode != null && !mapAccount.containsKey(ord.custcode)){
                	mapAccount.put(ord.custcode, ord.custcode);
                }
                if(!mapProduct.containsKey(ord.cinvbasid)){
                    mapProduct.put(ord.cinvbasid, ord.cinvbasid);
                }
                //如果当前记录的更新时间大于最大时间(maxTs)，则设置最大时间为当前记录时间
                Datetime dt = Utils.parseDatetime(ord.ts);
                if(dt > maxTs){
                    maxTs = dt;
                }
                if(dt < minTs){
                    minTs = dt;
                }
            }
        }
        //得到产品记录
        List<Product__c> productList = [SELECT Id,Name,NCCode__c,pk_invbasdoc__c FROM Product__c WHERE pk_invbasdoc__c IN :mapProduct.keySet()];
        mapProduct.clear();
        for(Product__c p : productList){
            mapProduct.put(p.pk_invbasdoc__c, p.Id);
        }
        //得到已存在的Order记录
        List<Order__c> ordList = [SELECT Id,Name,NCsale_hid__c,NCcorpcode__c,NCcorpname__c,
                                    NCcustcode__c,NCcustname__c,NCcurrtypename__c,NCywyname__c,NCkpdw__c,NCzdkh__c,
                                    Account__r.Id,Order_Date__c,Department__c,ShippingAddress__c,Receive_Agreement__c 
                            FROM Order__c 
                            WHERE NCsale_hid__c IN :mapCodes.keySet()];
        //把已存在的Order保存在Map中以用来区别是新增或更新
        Map<String,Order__c> mapExistOrder = new Map<String,Order__c>();
        for(Order__c ord : ordList){
            mapExistOrder.put(ord.NCsale_hid__c, ord);
        }

        //得到已存在的Order明细数据
        List<Order_Product__c> ordItemList = [SELECT Id,Name,NCsalecode__c,NCsale_hid__c,NCsale_bid__c,NCinvcode__c,Product__c,
                                NCinvdm__c,NCpzwh__c,NCnnum__c,Quote_Price__c,Original_Price__c,Order__r.Id  
                            FROM Order_Product__c 
                            WHERE NCsale_hid__c IN :mapCodes.keySet()];
        Map<String,Order_Product__c> mapExistOrderItem = new Map<String,Order_Product__c>();
        for(Order_Product__c item : ordItemList){
            mapExistOrderItem.put(item.NCsale_hid__c + '-' + item.NCsale_bid__c, item);
        }
        System.debug(LoggingLevel.INFO, '*** Exist Order On CRM: ' + ordList);
        System.debug(LoggingLevel.INFO, '*** Exist Order Detail On CRM: ' + ordItemList);

        //得到NC客户编号和CRM客户Id对应关系
        List<Account> accList = new List<Account>([SELECT Id,Name,AccountNumber FROM Account WHERE AccountNumber IN :mapAccount.keySet()]);
        mapAccount.clear();
        for(Account acc : accList){
            if(!mapAccount.containsKey(acc.AccountNumber)){
                mapAccount.put(acc.AccountNumber, acc.Id);
            }
        }
        ///用来保存从表pk的记录集合
        List<Map<String,String>> pkList = new List<Map<String,String>>();
        //用来保存或更新的订单主表的记录集合
        List<Order__c> saveList = new List<Order__c>();
        //用来保存或更新的订单从表的记录集合
        List<Order_Product__c> saveItemList = new List<Order_Product__c>();
        //用来记录主表记录是否已在下面的for循环中已操作
        Map<String,String> hasRunCodes = new Map<String,String>();
        //记录错误订单号
        String errOrderCodes = '';
        //记录系统中不存在客户代码
        String errAccountNumber = '';
        //新建或更新现存Order/Order_Product记录
        for(OrderRestArgs ord : data){
            if(mapAccount.containsKey(ord.custcode)){
                if(ord.sale_hid != null){
                    //如果主表记录已处理过了，则不再处理主表数据，只处理从表数据
                    if(!hasRunCodes.containsKey(ord.sale_hid)){
                        //记录本条记录的主表数据已处理过了
                        hasRunCodes.put(ord.sale_hid, '');
                        //主表数据
                        Order__c ordForSave = null;
                        if(mapExistOrder.containsKey(ord.sale_hid)){
                            ordForSave = mapExistOrder.get(ord.sale_hid);
                        }else{
                            ordForSave = new Order__c();
                        }
                        ordForSave.Name = ord.salecode;//销售订单号
                        //ordForSave.SerialNo__c = ord.salecode;//销售订单号
                        ordForSave.Account__c = mapAccount.get(ord.custcode);//客户Id
                        try{
                            ordForSave.Order_Date__c = Date.valueOf(ord.saledate);//订单日期
                        }
                        catch(Exception e){
                            ordForSave.Order_Date__c = null;//订单日期
                        }
                        ordForSave.Department__c = ord.deptname;//部门
                        ordForSave.ShippingAddress__c = ord.shaddr;//收货地址
                        ordForSave.Receive_Agreement__c = ord.skxy;//收款协议
                        ordForSave.NCsale_hid__c = ord.sale_hid;//销售订单主表ID
                        ordForSave.NCcorpcode__c = ord.corpcode;//公司编码
                        ordForSave.NCcorpname__c = ord.corpname;//公司名称
                        ordForSave.NCcustcode__c = ord.custcode;//客户编码
                        ordForSave.NCcustname__c = ord.custname;//客户名称
                        ordForSave.NCcurrtypename__c = ord.currtypename;//币种
                        ordForSave.NCywyname__c = ord.ywyname;//业务员
                        ordForSave.NCkpdw__c = ord.kpdw;//开票单位
                        ordForSave.NCzdkh__c = ord.zdkh;//终端客户

                        saveList.add(ordForSave);
                    }

                    //从表数据
                    Order_Product__c ordItem = null;
                    if(mapExistOrderItem.containsKey(ord.sale_hid + '-' + ord.sale_bid)){
                        ordItem = mapExistOrderItem.get(ord.sale_hid + '-' + ord.sale_bid);
                    }else{
                        ordItem = new Order_Product__c();
                    }
                    ordItem.NCsalecode__c = ord.salecode;//销售订单号
                    ordItem.NCsale_hid__c = ord.sale_hid;//销售订单主表ID
                    ordItem.NCsale_bid__c = ord.sale_bid;//销售订单从表ID
                    ordItem.Name = getName(ord.invname);//存货名称
                    ordItem.NCinvcode__c = ord.invcode;//存货编码
                    ordItem.NCinvdm__c = ord.invdm;//存货代码
                    ordItem.NCpzwh__c = ord.pzwh;//批准文号
                    ordItem.Product__c = mapProduct.containsKey(ord.cinvbasid)?mapProduct.get(ord.cinvbasid):null;//产品
                    ordItem.dr__c = ord.dr=='1'?true:false;//删除标记
                    try{
                        ordItem.Quote_Price__c = Decimal.valueOf(ord.noriginalcurtaxprice);//原币含税单价
                    }catch(Exception e){
                        ordItem.Quote_Price__c = 0;
                    }
                    try{
                        ordItem.Original_Price__c = Decimal.valueOf(ord.noriginalcurprice);//原币无税单价
                    }catch(Exception e){
                        ordItem.Original_Price__c = 0;
                    }
                    try{
                        ordItem.NCnnum__c = Decimal.valueOf(ord.nnum);//数量
                    }catch(Exception e){
                        ordItem.NCnnum__c = 0;
                    }
                    
                    ///拼接返回的主表pk 和字表pk 
                    Map<String,String> pk = new Map<String,String>();
                    pk.put('mainpk',ord.sale_hid);
                    pk.put('sonpk',ord.sale_bid);

                    pkList.add(pk);
                    saveItemList.add(ordItem);
                }
            }else{
                errOrderCodes += errOrderCodes.contains(ord.sale_hid + ',')?'':ord.sale_hid + ',';
                errAccountNumber += errAccountNumber.contains(ord.custcode + ',')?'':ord.custcode + ',';
            }
        }
        if(!String.isBlank(errOrderCodes)){
                message = Utils.getRestReturnMessage(false,'这些订单号有错误：' + errOrderCodes+';不存在的客户编号：' + errAccountNumber,new List<Map<String ,String>>());
                return message; 
   
            // message =  Utils.getRestReturnMessage(true, '这些订单号有错误：' + errOrderCodes + '不存在的客户编号：' + errAccountNumber + '部分数据导入失败,[成功导入记录条数：'+saveList.size()+']',maxTs);
            }
        //设置事务还原点，当操作失败时用来回滚
        SavePoint sp = Database.setSavePoint();
        try{
            //保存主表数据
            Upsert saveList NCsale_hid__c;
            //取得保存后的订单Id和NC销售订单号的对应关系
            mapCodes.clear();
            for(Order__c ord : saveList){
                if(!mapCodes.containsKey(ord.NCsale_hid__c)){
                    mapCodes.put(ord.NCsale_hid__c, ord.Id);
                }
            }
            //设置从表的OrderId
            for(Order_Product__c pro : saveItemList){
                pro.Order__c = mapCodes.containsKey(pro.NCsale_hid__c)?mapCodes.get(pro.NCsale_hid__c):null;
            }
            //保存从表数据
            Upsert saveItemList NCsale_bid__c;
        
            //在处理过程中没有有错误数据存在。
            if(String.isBlank(errOrderCodes)){
              	 message = Utils.getRestReturnMessage(true,'',pkList);
                //message = Utils.getRestReturnMessage(true,'数据导入成功[总条数：' + saveList.size() + ']',maxTs);
            }
        }
        catch(Exception e) {
            System.debug(LoggingLevel.INFO, '*** 错误信息: ' + e.getMessage() );
            System.debug(LoggingLevel.INFO, '*** 错误跟踪: ' + e.getStackTraceString());
            //保存数据失败，回滚事务
            Database.rollback(sp);
            message =  Utils.getRestReturnMessage(false, e.getMessage() + ' - ' + e.getStackTraceString(),new List<Map<String ,String>>());
        }

        return message; 
    }
    private static String getName(String name){
        if(String.isNotBlank(name) && name.length() > 80){
            return name.substring(0,79);
        }else{
            return name;
        }
    }
    //根据NC提供的JSON结构来确定的Order字段集合
    global class OrderRestArgs {
        //主表数据
        global String salecode;//销售订单号
        global String sale_hid;//销售订单主表ID
        global String corpcode;//公司编码
        global String corpname;//公司名称
        global String custcode;//客户编码
        global String custname;//客户名称
        global String currtypename;//币种
        global String saledate;//订单日期
        global String deptname;//部门
        global String ywyname;//业务员
        global String shaddr;//收货地址
        global String kpdw;//开票单位
        global String skxy;//收款协议
        global String zdkh;//终端客户
        //从表数据
        global String sale_bid;//销售订单从表ID
        global String invcode;//存货编码
        global String invname;//存货名称
        global String invdm;//存货代码
        global String pzwh;//批准文号
        global String nnum;//数量
        global String noriginalcurtaxprice;//原币含税单价
        global String noriginalcursummny;//原币价税合计
        global String noriginalcurprice;//原币无税单价
        global String noriginalcurmny;//原币无税金额
        global String ts;//最后更新时间
        //v1.4版本新增
        global String rowno;//行号
        global String invspec;//规格
        global String invtype;//型号
        global String cbiztype;//业务流程
        global String vsalestruname;//销售组织
        global String bodyname;//库存组织
        global String kpfs;//开票方式
        global String xsqy;//销售区域
        global String hbfs;//开票合并方式
        global String jshj;//整单价税合计
        global String memo;//备注
        global String tsyq;//客户特殊要求
        global String iszx;//是否直销
        global String prodlinename;//产品线
        global String ntaxrate;//税率
        global String jldw;//单位
        global String ndiscountrate;//整单折扣
        global String nitemdiscountrate;//单品折扣
        global String noriginalcurnetprice;//无税净价
        global String noriginalcurtaxnetprice;//含税净价
        global String noriginalcurdiscountmny;//折扣额
        global String tconsigntime;//计划发货时间
        global String jmb;//当前价目表
        global String norgqttaxprc;//报价单位本币含税单价
        //v1.5新增从表 nc那边传过来的数据里面多了一个dr字段，1或者0
        global String dr;
        global String cinvbasid;
    }
}